package com.chaintor.demo.math;

import org.apache.commons.math3.analysis.solvers.NewtonRaphsonSolver;
import org.apache.commons.math3.util.FastMath;

import java.util.Vector;

/**
 * 差分进化求解SABR的函数形式
 */
public class DiffEvolutionSABR implements DiffEvolutionOptimizable {
    private static final int m_dim = 2;

    private double m_beta;
    private double m_F;
    private double m_expToToday;
    private int m_atm_index;

    private double[] m_ks;
    private double[] m_sigmas;
    private SigmaSABRFunction[] m_sabrs;
    private SigmaSABRFunction m_sigmaSABRK;

    private double m_Alpha;

    public DiffEvolutionSABR(double[] ks,double[] sigmas,double f,double b,double exp_to_t,SigmaSABRFunction sigmaSABRK){
        m_atm_index = ks.length/2;
        m_ks = ks;
        m_sigmas = sigmas;
        m_F = f;
        m_beta = b;
        m_expToToday = exp_to_t;
        m_sabrs = new SigmaSABRFunction[m_ks.length];
        for(int i=0;i<m_ks.length;i++){
            m_sabrs[i] = new SigmaSABRFunction(m_F,m_ks[i],m_beta,m_expToToday);
        }
        m_sigmaSABRK = sigmaSABRK;
    }

    public double evaluteCost(double[] inputs) {
        double sumValue = 0.0;
        NewtonSolveSABRUnivariateDiffFunc ntsabrfunc = new NewtonSolveSABRUnivariateDiffFunc(m_sigmaSABRK,inputs[0],inputs[1],m_sigmas[m_atm_index]);
        YssNewtonRaphsonSolver ntSolver = new YssNewtonRaphsonSolver();
        m_Alpha = ntSolver.solve(30,ntsabrfunc,m_sigmas[m_atm_index]);
        for(int i=0;i<m_ks.length;i++){
            sumValue += FastMath.pow(m_sigmas[i]-m_sabrs[i].value(m_Alpha,inputs[1],inputs[0]),2);
        }
        return sumValue;
    }

    public int numberOfParameters() {
        return m_dim;
    }

    /**
     * 参数限制范围
     * @return
     */
    public Vector<Constraints> GetConstraints() {
        Vector<Constraints> vc = new Vector<Constraints>(2);
        Constraints consnu = new Constraints(0,10);
        vc.addElement(consnu);
        Constraints consrho = new Constraints(-1,1);
        vc.addElement(consrho);
        return vc;
    }

    public double getAlpha() {
        return this.m_Alpha;
    }
}
